#ifndef T_SERIALIZE_XML_FACADE_H

#define T_SERIALIZE_XML_FACADE_H

#include "../implement/inc/InternalCommon.h"
#include "../implement/inc/SerializeCommon.hpp"
#include "./TTypeDiscovery.h"

namespace SerializeObject
{

	struct ISerializeXmlOperator
	{
		virtual int Write(TiXmlElement	*element) = 0;
		virtual int Read(TiXmlElement	*element) = 0;
	};

	struct ISerializeXMLAttribute : public	ISerializeXmlOperator{};
	struct ISerializeXMLText : public ISerializeXmlOperator{};

	struct ISerializeXMLAttributePointer{};
	struct ISerializeXMLTextPointer{};

	template<typename T>
	class TSerializeXMLSmartPointer : public ISerializeXMLAttributePointer
	{
	public:
		TSerializeXMLSmartPointer(T *object)
		{
			m_object = object;
		}
		~TSerializeXMLSmartPointer()
		{
			FREE_POINT_SAFE(m_object);
		}
		operator T*()
		{
			return m_object;
		}
		int Write(TiXmlElement *element)
		{
			return m_object->Write(element);
		}
		int Read(TiXmlElement *element)
		{
			return m_object->Read(element);
		}
		int IsValid()
		{
			return ((CHECK_POINT_NO_NULL(m_object)) ? 0 : 1);
		}
	private:
		T	*m_object;
	};

	template<>
	class TSerializeXMLSmartPointer<ISerializeXMLText> : public ISerializeXMLTextPointer
	{
	public:
		TSerializeXMLSmartPointer(ISerializeXMLText *object)
		{
			m_object = object;
		}
		~TSerializeXMLSmartPointer()
		{
			FREE_POINT_SAFE(m_object);
		}
		operator ISerializeXMLText*()
		{
			return m_object;
		}
		int Write(TiXmlElement *element)
		{
			return m_object->Write(element);
		}
		int Read(TiXmlElement *element)
		{
			return m_object->Read(element);
		}
		int IsValid()
		{
			return ((CHECK_POINT_NO_NULL(m_object)) ? 0 : 1);
		}
	private:
		ISerializeXMLText	*m_object;
	};

	template<int flag>
	struct xml_writer_attribute
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target);
	};

	template<int flag>
	struct xml_reader_attribute
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target);
	};

	template<>
	struct xml_writer_attribute<byteType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target)
		{
			element->SetAttribute(caption, (BYTE)(*target));
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_attribute<byteType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target)
		{
			const char *attr = element->Attribute(caption);
			if (CHECK_POINT_NULL(attr))
			{
				return RET_FAIL;
			}
			(*target) = (T)atoi(attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_attribute<charpointerType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target)
		{
			element->SetAttribute(caption, *target);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_attribute<charpointerType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target)
		{
			const char *attr = element->Attribute(caption);
			if (CHECK_POINT_NULL(attr))
			{
				return RET_FAIL;
			}
			strcpy(target, attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_attribute<chararrayType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target)
		{
			element->SetAttribute(caption, *target);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_attribute<chararrayType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target)
		{
			const char *attr = element->Attribute(caption);
			if (CHECK_POINT_NULL(attr))
			{
				return RET_FAIL;
			}
			strcpy(*target, attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_attribute<shortType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target)
		{
			element->SetAttribute(caption, (WORD)(*target));
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_attribute<shortType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target)
		{
			const char *attr = element->Attribute(caption);
			if (CHECK_POINT_NULL(attr))
			{
				return RET_FAIL;
			}
			(*target) = (T)atoi(attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_attribute<longType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target)
		{
			element->SetAttribute(caption, (DWORD)(*target));
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_attribute<longType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target)
		{
			const char *attr = element->Attribute(caption);
			if (CHECK_POINT_NULL(attr))
			{
				return RET_FAIL;
			}
			(*target) = (T)atol(attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_attribute<floatType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target)
		{
			element->SetDoubleAttribute(caption, (double)(*target));
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_attribute<floatType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target)
		{
			const char *attr = element->Attribute(caption);
			if (CHECK_POINT_NULL(attr))
			{
				return RET_FAIL;
			}
			(*target) = (T)atof(attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_attribute<longlongType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, char *caption, T *target);
	};

	template<>
	struct xml_reader_attribute<longlongType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, char *caption, T *target);
	};

	template<int flag>
	struct xml_writer_text
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target);
	};

	template<int flag>
	struct xml_reader_text
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target);
	};

	template<>
	struct xml_writer_text<byteType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target)
		{
			char buffer[16];
			sprintf(buffer, "%d", *target);
			TiXmlText *xml = new TiXmlText(buffer);
			element->LinkEndChild(xml);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_text<byteType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target)
		{
			const char *text = element->GetText();
			if (CHECK_POINT_NULL(text))
			{
				return RET_FAIL;
			}
			(*target) = (T)atoi(attr);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_text<charpointerType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target)
		{
			TiXmlText *xml = new TiXmlText(target);
			element->LinkEndChild(xml);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_text<charpointerType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target)
		{
			const char *text = element->GetText();
			if (CHECK_POINT_NULL(text))
			{
				return RET_FAIL;
			}
			strcpy(target, text);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_text<shortType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target)
		{
			char buffer[16];
			sprintf(buffer, "%d", *target);
			TiXmlText *xml = new TiXmlText(buffer);
			element->LinkEndChild(xml);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_text<shortType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target)
		{
			const char *text = element->GetText();
			if (CHECK_POINT_NULL(text))
			{
				return RET_FAIL;
			}
			(*target) = (T)atoi(text);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_text<longType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target)
		{
			char buffer[16];
			sprintf(buffer, "%d", *target);
			TiXmlText *xml = new TiXmlText(buffer);
			element->LinkEndChild(xml);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_text<longType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target)
		{
			const char *text = element->GetText();
			if (CHECK_POINT_NULL(text))
			{
				return RET_FAIL;
			}
			(*target) = (T)atol(text);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_text<floatType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target)
		{
			char buffer[16];
			sprintf(buffer, "%.3f", *target);
			TiXmlText *xml = new TiXmlText(buffer);
			element->LinkEndChild(xml);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_reader_text<floatType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target)
		{
			const char *text = element->GetText();
			if (CHECK_POINT_NULL(text))
			{
				return RET_FAIL;
			}
			(*target) = (T)atof(text);
			return RET_SUCCESS;
		}
	};

	template<>
	struct xml_writer_text<longlongType>
	{
		template<typename T>
		static int Write(TiXmlElement *element, T *target);
	};

	template<>
	struct xml_reader_text<longlongType>
	{
		template<typename T>
		static int Read(TiXmlElement *element, T *target);
	};

	template<typename T_VALUE>
	class TSerializeXmlAttribute : public ISerializeXMLAttribute
	{
	public:
		TSerializeXmlAttribute()
		{
			Initialize();
		}
		virtual ~TSerializeXmlAttribute()
		{
			Initialize();
		}
	public:
		int SetLabel(char *Label)
		{
			m_Label = Label;
			return RET_SUCCESS;
		}
		int SetElement(T_VALUE *Value)
		{
			m_Value = Value;
			return RET_SUCCESS;
		}
		int Write(TiXmlElement *element)
		{
			return xml_writer_attribute<AtomicValue<T_VALUE>::value>::Write(element, m_Label, m_Value);
		}
		int Read(TiXmlElement *element)
		{
			return xml_reader_attribute<AtomicValue<T_VALUE>::value>::Read(element, m_Label, m_Value);
		}
	protected:
		DISABLE_COPY_CAPABILITY_OBJECT(TSerializeXmlAttribute);
	protected:
		int Initialize()
		{
			m_Label = NULL;
			m_Value = NULL;
			return RET_SUCCESS;
		}
	private:
		char	*m_Label;
		T_VALUE	*m_Value;
	};

	template<typename T_VALUE>
	class TSerializeXmlText : public ISerializeXMLText
	{
	public:
		TSerializeXmlText()
		{
			Initialize();
		}
		virtual ~TSerializeXmlText()
		{
			Initialize();
		}
	public:
		int SetElement(T_VALUE *Value)
		{
			m_Value = Value;
			return RET_SUCCESS;
		}
		int Write(TiXmlElement *element)
		{
			return xml_writer_text<AtomicValue<T_VALUE>::value>::Write(element, m_Value);
		}
		int Read(TiXmlElement *element)
		{
			return xml_reader_text<AtomicValue<T_VALUE>::value>::Read(element, m_Value);
		}
	protected:
		DISABLE_COPY_CAPABILITY_OBJECT(TSerializeXmlText);
	protected:
		int Initialize()
		{
			m_Value = NULL;
			return RET_SUCCESS;
		}
	private:
		T_VALUE	*m_Value;
	};

	template<eSerializeXmlElementType eType>
	struct build_xml_element
	{
		template<typename T> static TSerializeXmlAttribute<T>* build(const T &data, char *caption)
		{
			T &target = const_cast<T&>(data);
			TSerializeXmlAttribute<T> *xml = new TSerializeXmlAttribute<T>;
			if (CHECK_POINT_NULL(xml))
			{
				return xml;
			}
			xml->SetLabel(caption);
			xml->SetElement(&target);
			return xml;
		}
		typedef ISerializeXMLAttribute return_type;
	};

	template<>
	struct build_xml_element<eSerializeXmlElementText>
	{
		template<typename T> static TSerializeXmlText<T>* build(const T &data, char *caption)
		{
			T &target = const_cast<T&>(data);
			TSerializeXmlText<T> *xml = new TSerializeXmlText<T>;
			if (CHECK_POINT_NULL(xml))
			{
				return xml;
			}
			xml->SetElement(&target);
			return xml;
		}
		typedef ISerializeXMLText return_type;
	};

	template<int flag>
	struct xml_writer
	{
		template<typename T, typename PARA> static int writer(T &obj, PARA &para)
		{
			return obj.Write(para);
		}
	};

	template<>
	struct xml_writer<1>
	{
		template<typename T, typename PARA> static int writer(T &obj, PARA &para)
		{
			int ireturn = obj.EncoderBegin(para);
			if (RET_CHECK_SUCCESS(ireturn))
			{
				ireturn = para.SerializeOperator(obj);
				obj.EncoderEnd(para);
			}
			return ireturn;
		}
	};

	template<int flag>
	struct xml_reader
	{
		template<typename T, typename PARA> static int reader(T &obj, PARA &para)
		{
			return obj.Read(para);
		}
	};

	template<>
	struct xml_reader<1>
	{
		template<typename T, typename PARA> static int reader(T &obj, PARA &para)
		{
			int ireturn = obj.DecoderBegin(para);
			if (RET_CHECK_SUCCESS(ireturn))
			{
				ireturn = para.SerializeOperator(obj);
				obj.DecoderEnd(para);
			}
			return ireturn;
		}
	};

#define SERIALIZE(value)									\
	SERIALIZE_XML_ATTRIB_P1(value)

#define SERIALIZE_XML_ATTRIB_P1(value)						\
	SerializeObject::TSerializeXMLSmartPointer<SerializeObject::build_xml_element<SerializeObject::eSerializeXmlElementAttribute>::return_type>(SerializeObject::build_xml_element<SerializeObject::eSerializeXmlElementAttribute>::build(value, #value))

#define SERIALIZE_XML_ATTRIB_P2(value, caption)				\
	SerializeObject::TSerializeXMLSmartPointer<SerializeObject::build_xml_element<SerializeObject::eSerializeXmlElementAttribute>::return_type>(SerializeObject::build_xml_element<SerializeObject::eSerializeXmlElementAttribute>::build(value, caption))

#define SERIALIZE_XML(value, caption, type)					\
	SerializeObject::TSerializeXMLSmartPointer<SerializeObject::build_xml_element<type>::return_type>(SerializeObject::build_xml_element<type>::build(value, caption))

}

#endif
